From bd28f46e537255f328b34164184b85223f05e686 Mon Sep 17 00:00:00 2001
From: Daniel Kolesa <daniel@octaforge.org>
Date: Fri, 22 Oct 2021 02:56:25 +0200
Subject: [PATCH 4/7] enforce strictly usrmerged layout

---
 docs/framebuffer                 |  6 +++---
 hook-functions                   | 33 ++++++++++++++++++++++----------
 hooks/fsck                       |  8 ++++----
 hooks/keymap                     |  2 +-
 init                             | 15 ++++-----------
 initramfs-tools.7                | 12 ++++++------
 mkinitramfs                      | 24 ++++++++++++++---------
 scripts/functions                |  6 +++---
 scripts/init-top/all_generic_ide |  4 ++--
 scripts/init-top/keymap          |  4 ++--
 scripts/local                    |  2 +-
 scripts/local-premount/resume    |  4 ++--
 scripts/nfs                      |  4 ++--
 13 files changed, 68 insertions(+), 56 deletions(-)

diff --git a/docs/framebuffer b/docs/framebuffer
index 453ac8f..5c75e23 100644
--- a/docs/framebuffer
+++ b/docs/framebuffer
@@ -86,7 +86,7 @@ matroxfb)
 	;;
 intelfb|i810fb|i915)
 	# Needs AGP driver loaded
-	/sbin/modprobe intel-agp
+	/usr/bin/modprobe intel-agp
 	;;
 uvesafb)
 	# v86d requires /dev/zero and dev/mem, but udev haven't been started yet
@@ -99,9 +99,9 @@ esac
 
 if [ -n "${FB}" ]; then
 	unset MODPROBE_OPTIONS
-	/sbin/modprobe -q fbcon
+	/usr/bin/modprobe -q fbcon
 	# shellcheck disable=SC2086
-	/sbin/modprobe -q ${FB} ${OPTS}
+	/usr/bin/modprobe -q ${FB} ${OPTS}
 fi
 
 if [ -e /proc/fb ]; then
diff --git a/hook-functions b/hook-functions
index 95bd584..af6dec4 100644
--- a/hook-functions
+++ b/hook-functions
@@ -97,8 +97,8 @@ manual_add_modules()
 	# configuration lines and embedded softdep information is not
 	# processed.  So we run twice, with and without this option.
 	# shellcheck disable=SC2034
-	{ /sbin/modprobe --all --set-version="${version?}" --ignore-install --quiet --show-depends "$@";
-	  /sbin/modprobe --all --set-version="${version}" --quiet --show-depends "$@"; } |
+	{ /usr/bin/modprobe --all --set-version="${version?}" --ignore-install --quiet --show-depends "$@";
+	  /usr/bin/modprobe --all --set-version="${version}" --quiet --show-depends "$@"; } |
 	while read -r prefix kmod options ; do
 		if [ "${prefix}" != "insmod" ]; then
 			continue
@@ -153,6 +153,23 @@ add_builtin_firmware()
 	done
 }
 
+_sanitize_target() {
+	local target
+	target=$*
+	case "${target}" in
+	/bin/*) target="/usr/${target}" ;;
+	/sbin/*) target="/usr/bin/${target#/sbin/}" ;;
+	/usr/sbin/*) target="/usr/bin/${target#/usr/sbin/}" ;;
+	/lib/*) target="/usr/${target}" ;;
+	/lib32/*) target="/usr/lib/${target#/lib32/}" ;;
+	/lib64/*) target="/usr/lib/${target#/lib64/}" ;;
+	/usr/lib32/*) target="/usr/lib/${target#/usr/lib32/}" ;;
+	/usr/lib64/*) target="/usr/lib/${target#/usr/lib64/}" ;;
+	/lib*) target="/usr${target}" ;;
+	esac
+	printf "%s" "${target}"
+}
+
 # $1 = file type (for logging)
 # $2 = file to copy to initramfs
 # $3 (optional) Name for the file on the initramfs
@@ -172,10 +189,8 @@ copy_file() {
 		target="${target}/${src##*/}"
 	fi
 
-	# Canonicalise usr-merged target directories
-	case "${target}" in
-	/bin/* | /lib* | /sbin/*) target="/usr${target}" ;;
-	esac
+	# Sanitize target directories
+	target="$(_sanitize_target ${target})"
 
 	# check if already copied
 	[ -e "${DESTDIR}/${target}" ] && return 1
@@ -190,10 +205,8 @@ copy_file() {
 		# Update source for the copy
 		src="${link_target}"
 
-		# Canonicalise usr-merged target directories
-		case "${link_target}" in
-		/bin/* | /lib* | /sbin/*) link_target="/usr${link_target}" ;;
-		esac
+		# Sanitize target directories
+		link_target="$(_sanitize_target ${link_target})"
 
 		if [ "${link_target}" != "${target}" ]; then
 			[ "${verbose?}" = "y" ] && echo "Adding ${type}-link ${target}"
diff --git a/hooks/fsck b/hooks/fsck
index 000ce4e..01e47cc 100755
--- a/hooks/fsck
+++ b/hooks/fsck
@@ -85,7 +85,7 @@ prereqs)
 	;;
 esac
 
-if [ ! -x /sbin/fsck ]; then
+if [ ! -x /usr/bin/fsck ]; then
 	exit 0
 fi
 
@@ -98,13 +98,13 @@ if [ -z "$fsck_types" ]; then
 	exit 0
 fi
 
-copy_exec /sbin/fsck
-copy_exec /sbin/logsave
+copy_exec /usr/bin/fsck
+copy_exec /usr/bin/logsave
 
 for type in $fsck_types; do
 	if prog="$(command -v "fsck.${type}")"; then
 		copy_exec "$prog"
 	else
-		echo "W: /sbin/fsck.${type} doesn't exist, can't install to initramfs" >&2
+		echo "W: /usr/bin/fsck.${type} doesn't exist, can't install to initramfs" >&2
 	fi
 done
diff --git a/hooks/keymap b/hooks/keymap
index 64f8e6d..e2d4e55 100755
--- a/hooks/keymap
+++ b/hooks/keymap
@@ -20,7 +20,7 @@ if [ "$KEYMAP" != "y" ] && [ "$KEYMAP" != "Y" ]; then
 	exit 0
 fi
 
-if [ ! -x /bin/setupcon ]; then
+if [ ! -x /usr/bin/setupcon ]; then
 	echo "setupcon is missing. Please install the 'console-setup' package."
 	exit 0
 fi
diff --git a/init b/init
index 99c842f..b46f2e7 100755
--- a/init
+++ b/init
@@ -1,8 +1,7 @@
 #!/bin/sh
 
-# Default PATH differs between shells, and is not automatically exported
-# by klibc dash.  Make it consistent.
-export PATH=/sbin:/usr/sbin:/bin:/usr/bin
+# One true path
+export PATH=/usr/bin
 
 [ -d /dev ] || mkdir -m 0755 /dev
 [ -d /root ] || mkdir -m 0700 /root
@@ -62,7 +61,7 @@ export BOOT=
 export BOOTIF=
 export UBIMTD=
 export break=
-export init=/sbin/init
+export init=/usr/bin/init
 export readonly=y
 export rootmnt=/root
 export debug=
@@ -220,7 +219,7 @@ run_scripts /scripts/init-top
 
 maybe_break modules
 [ "$quiet" != "y" ] && log_begin_msg "Loading essential drivers"
-[ -n "${netconsole}" ] && /sbin/modprobe netconsole netconsole="${netconsole}"
+[ -n "${netconsole}" ] && /usr/bin/modprobe netconsole netconsole="${netconsole}"
 load_modules
 [ "$quiet" != "y" ] && log_end_msg
 
@@ -279,12 +278,6 @@ validate_init() {
 if ! validate_init "$init"; then
 	echo "Target filesystem doesn't have requested ${init}."
 	init=
-	for inittest in /sbin/init /etc/init /bin/init /bin/sh; do
-		if validate_init "${inittest}"; then
-			init="$inittest"
-			break
-		fi
-	done
 fi
 
 # No init on rootmount
diff --git a/initramfs-tools.7 b/initramfs-tools.7
index e25e455..4958df2 100644
--- a/initramfs-tools.7
+++ b/initramfs-tools.7
@@ -268,7 +268,7 @@ If you need to copy an executable or shared library to the initramfs
 module, use a command like this:
 .PP
 .RS
-copy_exec /sbin/mdadm /sbin
+copy_exec /usr/bin/mdadm /usr/bin
 .RE
 
 mkinitramfs will automatically detect which libraries it depends on
@@ -504,12 +504,12 @@ esac
 \fR. /usr/share/initramfs-tools/hook-functions
 # Begin real processing below this line
 
-if [ ! \-x "/sbin/frobnicate" ]; then
+if [ ! \-x "/usr/bin/frobnicate" ]; then
 	exit 0
 fi
 
 force_load frobnicator interval=10
-copy_exec /sbin/frobnicate /sbin
+copy_exec /usr/bin/frobnicate /usr/bin
 exit 0
 .fi
 .RE
@@ -537,7 +537,7 @@ esac
 
 \fR. /scripts/functions
 # Begin real processing below this line
-if [ ! \-x "/sbin/frobnicate" ]; then
+if [ ! \-x "/usr/bin/frobnicate" ]; then
 	panic "Frobnication executable not found"
 fi
 
@@ -546,7 +546,7 @@ if [ ! \-e "/dev/mapper/frobb" ]; then
 fi
 
 log_begin_msg "Starting frobnication"
-/sbin/frobnicate "/dev/mapper/frobb" || panic "Frobnication failed"
+/usr/bin/frobnicate "/dev/mapper/frobb" || panic "Frobnication failed"
 log_end_msg
 
 exit 0
@@ -581,7 +581,7 @@ Argument passed to the \fIpanic\fP helper function.  Use to find out why
 you landed in the initramfs shell.
 .TP
 \fB\fI init
-passes the path to init(8) usually /sbin/init.
+passes the path to init(8) usually /usr/bin/init.
 .TP
 \fB\fI readonly
 is the default for mounting the root corresponds to the ro bootarg.
diff --git a/mkinitramfs b/mkinitramfs
index 551d564..8152558 100755
--- a/mkinitramfs
+++ b/mkinitramfs
@@ -1,7 +1,7 @@
 #!/bin/sh
 
 umask 0022
-export PATH='/usr/bin:/sbin:/bin'
+export PATH='/usr/bin'
 
 # Defaults
 keep="n"
@@ -302,12 +302,18 @@ export __TMPCPIOGZ
 # Private, used by 'prepend_earlyinitramfs'.
 export __TMPEARLYCPIO
 
-# Create usr-merged filesystem layout, to avoid duplicates if the host
-# filesystem is usr-merged.
-for d in /bin /lib* /sbin; do
-	mkdir -p "${DESTDIR}/usr${d}"
-	ln -s "usr${d}" "${DESTDIR}${d}"
-done
+# one true layout
+mkdir -p "${DESTDIR}/usr/bin"
+ln -s "usr/bin" "${DESTDIR}/bin"
+ln -s "usr/bin" "${DESTDIR}/sbin"
+ln -s "bin" "${DESTDIR}/usr/sbin"
+mkdir -p "${DESTDIR}/usr/lib"
+ln -s "usr/lib" "${DESTDIR}/lib"
+ln -s "usr/lib" "${DESTDIR}/lib32"
+ln -s "usr/lib" "${DESTDIR}/lib64"
+ln -s "lib" "${DESTDIR}/usr/lib32"
+ln -s "lib" "${DESTDIR}/usr/lib64"
+
 for d in conf/conf.d etc run scripts ${MODULESDIR}; do
 	mkdir -p "${DESTDIR}/${d}"
 done
@@ -396,8 +402,8 @@ touch "${DESTDIR}/etc/fstab"
 ln -s /proc/mounts "${DESTDIR}/etc/mtab"
 
 # module-init-tools
-copy_exec /sbin/modprobe /sbin
-copy_exec /sbin/rmmod /sbin
+copy_exec /usr/bin/modprobe /usr/bin
+copy_exec /usr/bin/rmmod /usr/bin
 mkdir -p "${DESTDIR}/etc/modprobe.d" "${DESTDIR}/lib/modprobe.d"
 for file in /etc/modprobe.d/*.conf /lib/modprobe.d/*.conf ; do
 	if test -e "$file" || test -L "$file" ; then
diff --git a/scripts/functions b/scripts/functions
index ae11b96..ebd4b14 100644
--- a/scripts/functions
+++ b/scripts/functions
@@ -99,13 +99,13 @@ maybe_break()
 			else
 				opts="-v"
 			fi
-			/sbin/modprobe ${opts} -a i8042 atkbd ehci-pci ehci-orion \
+			/usr/bin/modprobe ${opts} -a i8042 atkbd ehci-pci ehci-orion \
 				 ehci-hcd ohci-hcd ohci-pci uhci-hcd usbhid xhci \
 				 xhci-pci xhci-hcd
 			sleep 2
 			for modalias in /sys/bus/hid/devices/*/modalias; do
 				if [ -f "${modalias}" ]; then
-					/sbin/modprobe ${opts} -b "$(cat "${modalias}")"
+					/usr/bin/modprobe ${opts} -b "$(cat "${modalias}")"
 				fi
 			done
 		fi
@@ -139,7 +139,7 @@ load_modules()
 				continue
 			fi
 			# shellcheck disable=SC2086
-			/sbin/modprobe $m
+			/usr/bin/modprobe $m
 		done < /conf/modules
 	fi
 }
diff --git a/scripts/init-top/all_generic_ide b/scripts/init-top/all_generic_ide
index cdf69cc..4f1bd4e 100755
--- a/scripts/init-top/all_generic_ide
+++ b/scripts/init-top/all_generic_ide
@@ -17,11 +17,11 @@ esac
 for x in $(cat /proc/cmdline); do
 	case ${x} in
 	all_generic_ide)
-		/sbin/modprobe ata_generic all_generic_ide=1
+		/usr/bin/modprobe ata_generic all_generic_ide=1
 		;;
 	all_generic_ide=*)
 		if [ -n "${x#all_generic_ide=}" ]; then
-			/sbin/modprobe ata_generic all_generic_ide=1
+			/usr/bin/modprobe ata_generic all_generic_ide=1
 		fi
 		;;
 	esac
diff --git a/scripts/init-top/keymap b/scripts/init-top/keymap
index 1c6b2dc..160cb61 100755
--- a/scripts/init-top/keymap
+++ b/scripts/init-top/keymap
@@ -13,6 +13,6 @@ prereqs)
 	;;
 esac
 
-if [ -x /bin/setupcon ]; then
-	/bin/setupcon
+if [ -x /usr/bin/setupcon ]; then
+	/usr/bin/setupcon
 fi
diff --git a/scripts/local b/scripts/local
index 8f9597f..8e45206 100644
--- a/scripts/local
+++ b/scripts/local
@@ -56,7 +56,7 @@ local_device_setup()
 	# Load ubi with the correct MTD partition and return since fstype
 	# doesn't work with a char device like ubi.
 	if [ -n "$UBIMTD" ]; then
-		/sbin/modprobe ubi "mtd=$UBIMTD"
+		/usr/bin/modprobe ubi "mtd=$UBIMTD"
 		DEV="${dev_id}"
 		return
 	fi
diff --git a/scripts/local-premount/resume b/scripts/local-premount/resume
index 63dcc49..b92e3de 100755
--- a/scripts/local-premount/resume
+++ b/scripts/local-premount/resume
@@ -40,7 +40,7 @@ fi
 
 # hardcode path, uswsusp ships an resume binary too
 if [ -n "${resume_offset?}" ]; then
-	/bin/resume "${DEV}" "${resume_offset}"
+	/usr/bin/resume "${DEV}" "${resume_offset}"
 else
-	/bin/resume "${DEV}"
+	/usr/bin/resume "${DEV}"
 fi
diff --git a/scripts/nfs b/scripts/nfs
index 26a969b..4608cd7 100644
--- a/scripts/nfs
+++ b/scripts/nfs
@@ -81,7 +81,7 @@ nfs_mount_root()
 	nfs_top
 
 	# For DHCP
-	/sbin/modprobe af_packet
+	/usr/bin/modprobe af_packet
 
 	wait_for_udev 10
 
@@ -130,7 +130,7 @@ nfs_mount_fs()
 	nfs_top
 
 	# For DHCP
-	/sbin/modprobe af_packet
+	/usr/bin/modprobe af_packet
 
 	wait_for_udev 10
 
-- 
2.37.1

